#include "codec.h"
#include <iostream>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}

namespace lcf
{
    /// 创建编码上下文
    /// @para codec_id 编码器ID号，对应ffmpeg
    /// @return 编码上下文 ,失败返回nullptr
    AVCodecContext *Codec::CreateContext(int codecId, bool isEncode)
    {
        // 1 找到编码器
        const AVCodec *codec = nullptr;

        codec = isEncode ? avcodec_find_encoder((AVCodecID)codecId) : avcodec_find_decoder((AVCodecID)codecId);
        if (!codec)
        {
            cerr << "avcodec_find_coder failed!" << codecId << endl;
            return nullptr;
        }
        // 创建上下文
        AVCodecContext *context = avcodec_alloc_context3(codec);
        if (!context)
        {
            cerr << "avcodec_alloc_context3 failed!" << codecId << endl;
            return nullptr;
        }
        // 设置参数默认值
        context->time_base = {1, 25};
        context->pix_fmt = AV_PIX_FMT_YUV420P;
        context->thread_count = 16;
        return context;
    }

    /// 设置对象的编码器上下文 上下文传递到对象中，资源由XEncode维护
    /// @para c 编码器上下文 如果c_不为nullptr，则先清理资源
    void Codec::SetContext(AVCodecContext *context)
    {
        unique_lock<mutex> lock(mtx_);
        if (context_)
        {
            avcodec_free_context(&context_);
        }
        context_ = context;
    }

    bool Codec::SetOpt(const char *key, const char *val)
    {
        unique_lock<mutex> lock(mtx_);
        if (!context_)
            return false;
        auto re = av_opt_set(context_->priv_data, key, val, 0);
        if (re != 0)
        {
            cerr << "av_opt_set failed!";
            PrintErr(re);
        }
        return true;
    }

    bool Codec::SetOpt(const char *key, int val)
    {
        unique_lock<mutex> lock(mtx_);
        if (!context_)
            return false;
        auto re = av_opt_set_int(context_->priv_data, key, val, 0);
        if (re != 0)
        {
            cerr << "av_opt_set failed!";
            PrintErr(re);
        }
        return true;
    }

    void Codec::Clear()
    {
        unique_lock<mutex> lock(mtx_);
        if (!context_)
            return;
        avcodec_flush_buffers(context_);
    }

    /// 打开编码器 线程安全
    bool Codec::Open()
    {
        unique_lock<mutex> lock(mtx_);
        if (!context_)
            return false;
        auto re = avcodec_open2(context_, NULL, NULL);
        if (re != 0)
        {
            PrintErr(re);
            return false;
        }
        return true;
    }
}
